﻿using System;
using System.Text;
using System.Windows.Forms;
using FacebookWrapper;
using FacebookWrapper.ObjectModel;
using Facebook;

namespace AutomaticAdvertising
{
    public partial class FormMain : Form
    {
        private const string k_DateTimeFormat = "dd/MM/yyyy HH:mm";
        private const int k_UpdateInterval = 10 * 60 * 1000; // 10 min
        private readonly DataHolder r_PostDataHolder = new DataHolder();
        private readonly Publisher r_Publisher = new Publisher();
        private readonly Scheduler r_ApplicationScheduler = new Scheduler();
        private User m_LoggedInUser;

        public FormMain()
        {
            InitializeComponent();

            r_PostDataHolder.Init();

            listBoxLikes.DisplayMember = "Name";
            listBoxComments.DisplayMember = "Name";
            checkedListBoxFriends.DisplayMember = "Name";
            listBoxUserPosts.DisplayMember = "Text";

            ListBox.CheckForIllegalCrossThreadCalls = false;
            RichTextBox.CheckForIllegalCrossThreadCalls = false;

            listBoxLikes.Sorted = true;
            checkedListBoxFriends.Sorted = true;

            FacebookService.s_CollectionLimit = 0;
        }

        private void buttonLogin_Click(object sender, EventArgs e)
        {
            try
            {
                updateStatusText("logging...");

                m_LoggedInUser = r_Publisher.Login();

                buttonLogin.Text = "logged in";
                buttonLogin.Enabled = false;
                
                mergeData();

                showUserInfo();

                showUserPosts();

                updateStatusText(string.Empty);

                r_ApplicationScheduler.Start(k_UpdateInterval);
                r_ApplicationScheduler.SchedulerTask += new ElapsedEventHandler(onSchedulerEvent);
            }
            catch (System.Exception ex)
            {
                updateStatusText("Login failed");
#if DEBUG
                MessageBox.Show(ex.Message + Environment.NewLine + ex.StackTrace.ToString());
#else
                MessageBox.Show(ex.Message);
#endif
            }    
        }

        private void showUserInfo()
        {
            pictureBoxUser.LoadAsync(m_LoggedInUser.PictureNormalURL);

            labelFriends.Text = string.Format("Friends ({0})", m_LoggedInUser.Friends.Count);

            checkedListBoxFriends.Items.Clear();

            foreach (User user in m_LoggedInUser.Friends)
            {
                checkedListBoxFriends.Items.Add(user);
            }
        }

        private void showUserPosts()
        {
            listBoxUserPosts.Items.Clear();
            listBoxLikes.Items.Clear();
            listBoxComments.Items.Clear();
            pictureBoxPostImage.Image = null;
            pictureBoxPostImage.Invalidate();
            richTextBoxPostInformation.Clear();
            richTextBoxComments.Clear();

            labelPosts.Text = string.Format("Posts ({0})", r_PostDataHolder.Count);
            
            foreach (PostData postData in r_PostDataHolder)
            {
                if (postData.Status != PostData.eStatus.deleted)
                {
                    listBoxUserPosts.Items.Add(postData);
                }
            }

            if (listBoxUserPosts.Items.Count > 0)
            {
                listBoxUserPosts.SelectedIndex = 0;
            }
            else
            {
                this.Invoke(new EventHandler(listBoxUserPosts_SelectedIndexChanged), new object[] { EventArgs.Empty });
            }

            buttonManualSync.Enabled = true;
            buttonCreatepost.Enabled = true;
        }

        private void listBoxUserPosts_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (listBoxUserPosts.SelectedIndex == -1)
            {
                prepareViewForNewData();
            }
            else
            {
                PostData postData = listBoxUserPosts.SelectedItem as PostData;

                updateLikersList(postData);
                updateCommentatorsList(postData);
                updateInformationList(postData);
            }
            
            buttonEditPost.Enabled = listBoxUserPosts.SelectedIndex != -1;
            buttonDeletePost.Enabled = listBoxUserPosts.SelectedIndex != -1;
        }

        private void updateLikersList(PostData i_PostData)
        {
            if (i_PostData.Status == PostData.eStatus.posted)
            {
                listBoxLikes.Items.Clear();

                labelLikedBy.Text = string.Format("Liked By {0} Users", i_PostData.Photo.LikedBy.Count);
                
                foreach (User user in i_PostData.Photo.LikedBy)
                {
                    listBoxLikes.Items.Add(user);
                }
            }
        }

        private void updateCommentatorsList(PostData i_PostData)
        {
            if (i_PostData.Status == PostData.eStatus.posted)
            {
                listBoxComments.Items.Clear();

                labelCommentedBy.Text = string.Format("Commented by {0} users", i_PostData.Photo.Comments.Count);

                foreach (Comment comment in i_PostData.Photo.Comments)
                {
                    listBoxComments.Items.Add(comment.From);
                }

                foreach (Comment comment in i_PostData.Photo.Comments)
                {
                    richTextBoxComments.AppendText(string.Format(comment.Message + Environment.NewLine));
                }
            }
        }

        private void updateInformationList(PostData i_PostData)
        {
            if (i_PostData.Status == PostData.eStatus.posted)
            {
                richTextBoxPostInformation.Text = string.Format(
@"Publish Date: {0}", Convert.ToDateTime(i_PostData.Photo.CreatedTime).ToString(k_DateTimeFormat));

                if (!string.IsNullOrEmpty(i_PostData.Photo.URL))
                {
                    pictureBoxPostImage.LoadAsync(i_PostData.Photo.URL);
                }
                else
                {
                    MessageBox.Show("Empty image path");
                }
            }
            else
            {
                richTextBoxPostInformation.Text = string.Format(
@"
Not Published");
                if (!string.IsNullOrEmpty(i_PostData.ImageLocalPath))
                {
                    pictureBoxPostImage.LoadAsync(i_PostData.ImageLocalPath);
                }
                else
                {
                    MessageBox.Show("Empty image path");
                }
            }

            if (i_PostData.StartDate > DateTime.MinValue)
            {
                richTextBoxPostInformation.AppendText(string.Format(
@"
StartDate: {0}
EndDate: {1}", 
             i_PostData.StartDate.ToString(k_DateTimeFormat), 
             i_PostData.EndDate.ToString(k_DateTimeFormat)));
            }
            else
            {
                richTextBoxPostInformation.AppendText(string.Format(
@"
Posted from Web", 
                i_PostData.StartDate.ToString(k_DateTimeFormat)));
            }
        }

        private void prepareViewForNewData()
        {
            richTextBoxPostInformation.Clear();
            richTextBoxComments.Clear();

            updateStatusText(string.Empty);

            pictureBoxPostImage.Image = null;
            pictureBoxPostImage.Invalidate();
        }
                     
        private void buttonOpenEditor_Click(object sender, EventArgs e)
        {
            PostEditor postEditor = new PostEditor(k_DateTimeFormat);
            
            r_ApplicationScheduler.Pause();
            
            if (postEditor.ShowDialog(this) == DialogResult.OK)
            {
                r_PostDataHolder.Add(postEditor.ReturnValue);

                showUserPosts();
            }

            r_ApplicationScheduler.Resume();
        }
        
        private void mergeData()
        {
            foreach (Post post in m_LoggedInUser.Posts)
            {
                if (post.Type == Post.eType.photo)
                {
                    r_PostDataHolder.MergeWithLocal(post);
                }
            }
        }
        
        private void synchronizeWithWeb()
        {
            updateStatusText("Processing please wait");

            r_ApplicationScheduler.Pause();
  
            foreach (PostData postData in r_PostDataHolder)
            {
                // upload new posts
                if (postData.Status == PostData.eStatus.notPosted)
                {
                    if (postData.StartDate <= DateTime.Now && postData.EndDate > DateTime.Now)
                    {
                        postData.Status = PostData.eStatus.posted;

                        Post post = r_Publisher.PostAdvertisement(postData);

                        postData.Id = post.Id;
                    }
                }
                else if (postData.Status == PostData.eStatus.posted)
                {
                    // delete oldest posts
                    if (DateTime.Now > postData.EndDate || DateTime.Now < postData.StartDate)
                    {
                        if (postData.StartDate > DateTime.Now)
                        {
                            postData.Status = PostData.eStatus.notPosted;
                        }
                        else
                        {
                            postData.Status = PostData.eStatus.deleted;
                        }

                        r_Publisher.DeletePostAdvertisement(postData);
                    }
                }
            }

            r_ApplicationScheduler.Resume();

            refresh();

            updateStatusText("All Data was synchronized");
        } 
        
        private void refresh()
        {
            r_ApplicationScheduler.Pause();

            m_LoggedInUser = r_Publisher.Refresh();

            r_ApplicationScheduler.Resume();

            mergeData();

            showUserPosts();
        }

        private void listBoxComments_SelectedIndexChanged(object sender, EventArgs e)
        {
            User user = listBoxComments.SelectedItem as User;

            if (user != null)
            {
                showFriendInFriendList(user);

                listBoxLikes.SelectedItem = null;
            }
        }
        
        private void buttonDeletePost_Click(object sender, EventArgs e)
        {
            updateStatusText("Deleting from server");
            
            r_PostDataHolder.Remove(listBoxUserPosts.SelectedItem as PostData);

            r_Publisher.DeletePostAdvertisement(listBoxUserPosts.SelectedItem as PostData);

            refresh();
        }
        
        private void removeItemDeletedFromServer(string i_Id)
        {
            foreach (PostData postData in r_PostDataHolder)
            {
                if (postData.Id == i_Id)
                {
                    r_PostDataHolder.Remove(postData);
                    break;
                }
            }
        }
        
        private void showFriendInFriendList(User friend)
        {
            foreach (User item in checkedListBoxFriends.Items)
            {
                if (item.Id == friend.Id)
                {
                    checkedListBoxFriends.SelectedItem = item;
                    break;
                }
            }
        }

        private void listBoxSelectedFriends_SelectedIndexChanged(object sender, EventArgs e)
        {
            User user = listBoxLikes.SelectedItem as User;

            if (user != null)
            {
                showFriendInFriendList(user);

                listBoxComments.SelectedItem = null;
            }
        }

        private void buttonEdit_Click(object sender, EventArgs e)
        {
            PostData postDataForEdit = listBoxUserPosts.SelectedItem as PostData;

            int i = r_PostDataHolder.IndexOf(postDataForEdit);

            if (i != -1)
            {
                PostEditor postEditor = new PostEditor(postDataForEdit, k_DateTimeFormat);

                if (postEditor.ShowDialog(this) == DialogResult.OK)
                {
                    r_PostDataHolder.RemoveAt(i);

                    r_PostDataHolder.Insert(i, postEditor.ReturnValue);

                    showUserPosts();
                }
            }
            else
            {
                MessageBox.Show("Please select Item for edit");
            }
        }

        private void FormMain_Load(object sender, EventArgs e)
        {
        }

        private void listBoxUserPosts_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            this.Invoke(new EventHandler(buttonEdit_Click), new object[] { EventArgs.Empty });
        }

        private void checkedListBoxFriends_SelectedIndexChanged(object sender, EventArgs e)
        {
            User selectedFriend = checkedListBoxFriends.SelectedItem as User;

            if (selectedFriend != null)
            {
                r_ApplicationScheduler.Pause();

                pictureBoxFriend.Image = null;
                pictureBoxFriend.Invalidate();
                richTextBoxFriendInfo.Clear();
                
                try
                {
                    string selectedFriendInfo = string.Format(
@"Name - {0}
Location - {1}
Birthday - {2}
Email - {3}
RelationshipStatus - {4},
Activity: 
    has {5} posted links 
    has {6} checkins 
    tagged on {7} photos 
    has {8} posts ({10} of them on wall) 
    post {9} videos 
    has {11} albums 
    speaks: {12}",
                 selectedFriend.Name, 
                 (selectedFriend.Location == null ? string.Empty : selectedFriend.Location.Name),
                 selectedFriend.Birthday,
                 selectedFriend.Email,
                 selectedFriend.RelationshipStatus,
                 selectedFriend.PostedLinks.Count,
                 selectedFriend.Checkins.Count,
                 selectedFriend.PhotosTaggedIn.Count,
                 selectedFriend.Posts.Count,
                 selectedFriend.Videos.Count,
                 selectedFriend.WallPosts.Count,
                 selectedFriend.Albums.Count,
                 formatLanguagesList(selectedFriend.Languages));
                    
                    richTextBoxFriendInfo.Text = selectedFriendInfo;
                }
                catch (System.Exception ex)
                {
#if DEBUG
                    updateStatusText(ex.Message + Environment.NewLine + ex.StackTrace.ToString());
#else
                    updateStatusText(ex.Message);
#endif
                }

                if (!string.IsNullOrEmpty(selectedFriend.PictureNormalURL))
                {
                    pictureBoxFriend.LoadAsync(selectedFriend.PictureNormalURL);
                }

                r_ApplicationScheduler.Resume();
            }
        }

        private string formatLanguagesList(Page[] i_Languages)
        {
            string formatedLanguagesList = string.Empty;

            if (i_Languages != null)
            {
                foreach (Page page in i_Languages)
                {
                    formatedLanguagesList += string.Format(
@"
        {0}", 
            page.Name);
                }
            }

            return formatedLanguagesList;
        }

        private void checkedListBoxFriends_ItemCheck(object sender, ItemCheckEventArgs e)
        {
            if (e.NewValue == CheckState.Unchecked)
            {
                if (checkedListBoxFriends.CheckedItems.Count == 1)
                {
                    buttonSendThanks.Enabled = false;
                }
            }
            else
            {
                buttonSendThanks.Enabled = true;
            }
        }

        private void buttonSendThanks_Click(object sender, EventArgs e)
        {
            MessageEditor messageEditor = new MessageEditor();

            if (messageEditor.ShowDialog(this) == DialogResult.OK)
            {
                string messageForFriends = string.Format(
@"Message for:
");
                foreach (User selectedFriend in checkedListBoxFriends.CheckedItems)
                {
                    messageForFriends += selectedFriend.Name + Environment.NewLine;
                }

                messageForFriends += messageEditor.ReturnValue;

                r_Publisher.PostOnFriensWall(messageForFriends);
            }   
        }

        private void onSchedulerEvent(object Scheduler, EventArgs e)
        {
            synchronizeWithWeb();
        }

        private void buttonManualSync_Click(object sender, EventArgs e)
        {
            buttonManualSync.Enabled = false;

            synchronizeWithWeb();
        }

        private void updateStatusText(string i_Status)
        {
            toolStripStatusLabel.Text = i_Status;
        }
    }
}
